package jp.sourceforge.akjrcp.text_douga.video;

import java.io.IOException;
import java.math.BigDecimal;

import jp.sourceforge.akjrcp.ffmpeg.FFMpegJpegPipeReader;
import jp.sourceforge.akjrcp.ffmpeg.JpegPipeReader;
import jp.sourceforge.akjrcp.ffmpeg.ProcessListener;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

public class VideoImageInput implements ProcessListener{
	public static Log log=LogFactory.getLog(VideoImageInput.class);
private double fps=30;
private int width=640;
private int height=480;

public static final int NOT_SPECIFIED=-1;
private String ffmpegPath;
private String inputPath;
private double startTime;
private double duration=NOT_SPECIFIED;

private boolean copying;
private boolean canceling;
private FFMpegJpegPipeReader ffreader;
private JpegPipeReader pipeReader;

private JpegKeeper jpegKeeper;

public VideoImageInput(String ffmpegPath,String inputPath) throws IOException{
	this(ffmpegPath,inputPath,0,NOT_SPECIFIED);
}

public VideoImageInput(String ffmpegPath,String inputPath,double start,double duration) throws IOException{
	this.ffmpegPath=ffmpegPath;
	this.inputPath=inputPath;
	this.startTime=start;
	this.duration=duration;
	
	pipeReader=new JpegPipeReader();
	jpegKeeper=new JpegKeeper();
}



public void startInput(){
	ffreader = new FFMpegJpegPipeReader(ffmpegPath,inputPath,new String[]{"-r",""+fps,"-s",width+"x"+height});
	ffreader.setProcessPrinter(null);//for speed up?
	ffreader.setJpegPipeReader(pipeReader);
	Thread t=new Thread(ffreader);
	ffreader.setProcessListener(this);
	t.start();
	copying=true;
}

public void finished() {
	copying=false;//
	log.info("done");
	
}

public void started() {
	int index=1;
	byte[] jpegData;
	log.info("started");
	int skipFrame=0;
	if(startTime>0){
		double fps_time=fps*startTime;
		
		BigDecimal dec = new BigDecimal(fps_time);
		skipFrame=dec.setScale(0,BigDecimal.ROUND_HALF_UP).intValue();
		log.info("fps_time="+fps_time+" skipFrame="+skipFrame);
		}
	//skip;
	for(int i=0;i<skipFrame;i++){
		jpegData=pipeReader.nextImage();
		if(jpegData==null){
			//skipped all;
			jpegKeeper.setFinished(true);
			
			copying=false;
			return;//done
		}
	}
	log.info("skipped:"+skipFrame);
	
	int durationFrame=0;
	if(duration>0){
		double duration_time=fps*duration;
		BigDecimal dec = new BigDecimal(duration_time);
		durationFrame=dec.setScale(0,BigDecimal.ROUND_HALF_UP).intValue();
		log.info("fps_time="+duration_time+" skipFrame="+durationFrame);
	}
	int writeFrame=0;
	
	while((jpegData=pipeReader.nextImage())!=null){
		if(canceling){
			break;
		}
		log.trace("add");
		jpegKeeper.addImage(jpegData);
		index++;
		writeFrame++;
		if(writeFrame==durationFrame){ //never durationFrame!=0
			try {
				pipeReader.close();
			} catch (IOException e) {
				e.printStackTrace();
			}//done no more.
			break;
		}
	}
	
	if(canceling){
		try {
			pipeReader.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	log.info("finished: writed="+writeFrame);
	//finished
	jpegKeeper.setFinished(true);
	copying=false;
	
	
	//kill process for perfect finish
	try {
		//i don't know reason why
		Thread.sleep(1000);
	} catch (InterruptedException e) {
		e.printStackTrace();
	}
	ffreader.getProcess().destroy();//good bye;
	/*
	try {
		BufferedInputStream binput = new BufferedInputStream(ffreader.getPCMPipeReader().getInputStream());
		long skipbyte=0;
		if(startTime!=0){
			skipbyte=(int)(rate*startTime*(2*channel));//2=16bit;
		}
		log.info("hope skip:"+skipbyte);
		long mustread=0;
		if(duration!=NOT_SPECIFIED){
			mustread=(int)(rate*duration*(2*channel));
		}
		//skip input
		long skipped=0;
		byte bts2[]=new byte[1024];
		while(skipped<skipbyte){
			int r;
			if(skipped+bts2.length<skipbyte){
				r=bts2.length;
			}else{
				r=(int) (skipbyte-skipped);
			}
			int readed=binput.read(bts2,0,r);
			skipped+=readed;//take care
			if(readed==-1){//enough
				break;
			}
		}
		if(skipped>0){
			log.info("skipped:"+skipped);
		}
		
		byte bytes[]=new byte[1024];
		long readed=0;
		int read=0;
		while(read!=-1){
			if(canceling){
				break;
			}
			read = binput.read(bytes, 0, bytes.length);
			
			if(read!=-1){
				
				if(duration!=NOT_SPECIFIED){
					if(readed+read<mustread){
						outputStream.write(bytes,0,read);
					}else{
						int canwrite=(int)(mustread-readed);
						outputStream.write(bytes,0,canwrite);
						readed+=canwrite;
						break;
					}
				}else{
					//just write
					outputStream.write(bytes,0,read);
				}
				readed+=read;
			}
		}
		log.info("readed:"+readed);
		
		if(!canceling){
		if(duration!=NOT_SPECIFIED){
			//fill space 
			byte bts[]=new byte[1024];
			long writed=readed;
			while(writed<mustread){
				int w;
				if(writed+bts.length<mustread){
					w=bts.length;
				}else{
					w=(int)(mustread-writed);
				}
				outputStream.write(bts,0,w);
				writed+=bts.length;
			}
			log.info("filled:"+writed);
		}
		}
		outputStream.close();
		
	} catch (UnsupportedAudioFileException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}finally{
		copying=false;//done
	}*/
}

public boolean isCanceling() {
	return canceling;
}

public void setCanceling(boolean canceling) {
	this.canceling = canceling;
}



public boolean isCopying() {
	return copying;
}

public void setCopying(boolean copying) {
	this.copying = copying;
}

public double getDuration() {
	return duration;
}

public void setDuration(double duration) {
	this.duration = duration;
}

public String getFfmpegPath() {
	return ffmpegPath;
}

public void setFfmpegPath(String ffmpegPath) {
	this.ffmpegPath = ffmpegPath;
}



public String getInputPath() {
	return inputPath;
}

public void setInputPath(String inputPath) {
	this.inputPath = inputPath;
}




public double getStartTime() {
	return startTime;
}

public void setStartTime(double startTime) {
	this.startTime = startTime;
}

public JpegKeeper getJpegKeeper() {
	return jpegKeeper;
}

public void setJpegKeeper(JpegKeeper jpegKeeper) {
	this.jpegKeeper = jpegKeeper;
}

public double getFps() {
	return fps;
}

public void setFps(double fps) {
	this.fps = fps;
}

public int getHeight() {
	return height;
}

public void setHeight(int height) {
	this.height = height;
}

public int getWidth() {
	return width;
}

public void setWidth(int width) {
	this.width = width;
}




}
